diff options
author | Wolfgang Beck <wolfgang.beck@nokia.com> | 2012-04-27 12:25:03 +1000 |
---|---|---|
committer | Wolfgang Beck <wolfgang.beck@nokia.com> | 2012-04-30 07:24:24 +0200 |
commit | 73382e5229b90220a1be3de30df93b42d977c148 (patch) | |
tree | 8653b6ee51e27990f33e4f7b061a4670bb1dd3e1 | |
parent | 27bf83ee9a211154eb88494ee3e7810d953020f8 (diff) |
Ensure Filewatcher is created on the Application thread.
Change-Id: I6e8a41408801103c2013e3e30adf83f4f3d6bb93
Reviewed-by: Lincoln Ramsay <lincoln.ramsay@nokia.com>
-rw-r--r-- | src/logger/qlogger.cpp | 45 | ||||
-rw-r--r-- | src/logger/qlogger_p.h | 17 | ||||
-rw-r--r-- | tests/auto/auto.pro | 3 | ||||
-rw-r--r-- | tests/auto/loggerenvar/loggerenvar.pro | 7 | ||||
-rw-r--r-- | tests/auto/loggerenvar/tst_qloggerenvar.cpp | 258 |
5 files changed, 317 insertions, 13 deletions
diff --git a/src/logger/qlogger.cpp b/src/logger/qlogger.cpp index 539c523..655fd3e 100644 --- a/src/logger/qlogger.cpp +++ b/src/logger/qlogger.cpp @@ -47,6 +47,8 @@ #include <QStandardPaths> #include <QBuffer> #include <QFileSystemWatcher> +#include <QThread> +#include <QCoreApplication> #include "qlogger_p.h" QT_USE_NAMESPACE @@ -115,13 +117,15 @@ namespace QLoggingCategories bool isEnabled() { - if (gEnvironment == EnvironmentNotChecked) checkEnvironment(); + if (gEnvironment == EnvironmentNotChecked) + checkEnvironment(); return gEnabled; } bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type) { - if (!isEnabled()) return false; + if (!isEnabled()) + return false; return qLogging()->isEnabled(category, type); } @@ -221,14 +225,25 @@ void qSetLoggingRules(const QByteArray &rules) +/*! + \internal For Autotest + */ +QLoggingPrivate *qtLoggerInstance() +{ + return qLogging(); +} /*! \internal QLoggingPrivate constructor */ QLoggingPrivate::QLoggingPrivate() - : _configFileWatcher(0) + : QObject(0) + , _configFileWatcher(0) { + //Move object to the application thread + this->moveToThread(QCoreApplication::instance()->thread()); + //add default category _registeredCategories.append(&QLoggingCategories::default_QLoggingCategory); } @@ -269,17 +284,28 @@ void QLoggingPrivate::setLoggingRulesFile(const QString &path) //Create filewatcher only if a config file exists if (!_configFileWatcher) { - _configFileWatcher = new QFileSystemWatcher(this); - connect(_configFileWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); + //This function can be called from a different thread. + //The creation of the filewatcher needs to be in the application thread. + //So we invoke the function that creates the filewatcher + QMetaObject::invokeMethod(this, "createFileWatcher"); } + QFile cfgfile(_configFile); + readSettings(cfgfile); +} + +/*! + \internal + Invokable function to create the System File Watcher on the applicationthread. +*/ +void QLoggingPrivate::createFileWatcher() +{ + _configFileWatcher = new QFileSystemWatcher(this); + connect(_configFileWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); QStringList oldfiles = _configFileWatcher->files(); if (!oldfiles.isEmpty()) _configFileWatcher->removePaths(oldfiles); _configFileWatcher->addPath(_configFile); - - QFile cfgfile(_configFile); - readSettings(cfgfile); } /*! @@ -348,6 +374,9 @@ void QLoggingPrivate::readSettings(QIODevice &device) gEnabled = true; } +#ifdef QT_BUILD_INTERNAL + emit configurationChanged(); +#endif } /*! diff --git a/src/logger/qlogger_p.h b/src/logger/qlogger_p.h index 7f18b9b..af91e46 100644 --- a/src/logger/qlogger_p.h +++ b/src/logger/qlogger_p.h @@ -81,14 +81,20 @@ public: void setLoggingRules(const QByteArray &configcontent); bool isEnabled(QLoggingCategories::QLoggingCategory &category, QtMsgType type); -private slots: - void fileChanged(const QString &path); + Q_INVOKABLE void createFileWatcher(); -private: void readSettings(QIODevice &device); void updateCategory(QLoggingCategories::QLoggingCategory *log); -private: +#ifdef QT_BUILD_INTERNAL +Q_SIGNALS: + void configurationChanged(); +#endif + +public slots: + void fileChanged(const QString &path); + +public: QFileSystemWatcher *_configFileWatcher; QList<QLoggingCategories::QLoggingCategory *> _registeredCategories; QString _configFile; @@ -96,6 +102,9 @@ private: QList<QLogConfigFilterItem> _logConfigItemList; }; +Q_AUTOTEST_EXPORT QLoggingPrivate *qtLoggerInstance(); + + QT_END_HEADER QT_LOGGER_END_NAMESPACE diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 8cda6e3..147aee7 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs SUBDIRS += \ - logger + logger \ + loggerenvar diff --git a/tests/auto/loggerenvar/loggerenvar.pro b/tests/auto/loggerenvar/loggerenvar.pro new file mode 100644 index 0000000..3d8c8a2 --- /dev/null +++ b/tests/auto/loggerenvar/loggerenvar.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = loggerenvar + +CONFIG += testcase +QT = core testlib logger-private + +SOURCES += tst_qloggerenvar.cpp diff --git a/tests/auto/loggerenvar/tst_qloggerenvar.cpp b/tests/auto/loggerenvar/tst_qloggerenvar.cpp new file mode 100644 index 0000000..668ce3a --- /dev/null +++ b/tests/auto/loggerenvar/tst_qloggerenvar.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtLogger/QtLogger> +#include <private/qlogger_p.h> +#include <QtTest/QtTest> +#include <QFile> +#include <QMutexLocker> +#include <QtCore/qlogging.h> + +// redefine qDebug & Co because we don't want to use QtLogger if test application starts up. +#if defined(qDebug) +# undef qDebug +#endif +#define qDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug +#if defined(qWarning) +# undef qWarning +#endif +#define qWarning QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).warning +#if defined(qCritical) +# undef qCritical +#endif +#define qCritical QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).critical + + +QT_LOG_CATEGORY(My_Category_A, "My.Category.A") +QT_LOG_CATEGORY(My_Category_B, "My.Category.B") +QT_LOG_CATEGORY(My_Category_C, "My.Category.C") +#define LOGRULEFILE "./myLogRules.txt" + +QT_USE_NAMESPACE + +QMessageHandler oldMessageHandler; +bool logReceived = false; +QMutex threadmutex; + +QByteArray qMyMessageFormatString(QtMsgType type, const QMessageLogContext &context, + const char *str) +{ + QByteArray message; + { + message.append(str); + message.append('\n'); + } + + return message; +} + +static void myCustomMessageHandler(QtMsgType type, const QMessageLogContext &context, const char *msg) +{ + QMutexLocker locker(&threadmutex); + QString logmsg = qMyMessageFormatString(type, context, msg); + if (logmsg.indexOf("My_Category") >= 0) { + logReceived = true; + } + else + oldMessageHandler(type, context, msg); +} + +class LogRules +{ +public: + LogRules() + { + } + + void addKey(const QString &key, bool val){ + //old key values gets updated + _values.insert(key, (val ? "true" : "false")); + if (!_configitemEntryOrder.contains(key)) + _configitemEntryOrder.append(key); + } + + QByteArray array() + { + QString ret; + QTextStream out(&ret); + for (int a = 0; a < _configitemEntryOrder.count(); a++) { + out << _configitemEntryOrder[a] << " = " << _values.value(_configitemEntryOrder[a]) << endl; + } + out.flush(); + return ret.toLatin1(); + } + + void clear() + { + _values.clear(); + _configitemEntryOrder.clear(); + } + +private: + QMap<QString, QString> _values; + QStringList _configitemEntryOrder; +}; + +class LogThread : public QThread +{ +public: + LogThread() {} + +protected: + void run(); +}; + +void LogThread::run() +{ + qCDebug(My_Category_A) << "My_Category_A"; + qCDebug(My_Category_B) << "My_Category_B"; + qCDebug(My_Category_C) << "My_Category_C"; + + qCWarning(My_Category_A) << "My_Category_A"; + qCWarning(My_Category_B) << "My_Category_B"; + qCWarning(My_Category_C) << "My_Category_C"; + + qCCritical(My_Category_A) << "My_Category_A"; + qCCritical(My_Category_B) << "My_Category_B"; + qCCritical(My_Category_C) << "My_Category_C"; +} + +LogRules logRules; + +class WriteFileThread : public QThread +{ +public: + WriteFileThread() + {} + +protected: + void run() + { + if (QFile::exists(LOGRULEFILE)) + QFile::remove(LOGRULEFILE); + QFile file(LOGRULEFILE); + if (file.open(QIODevice::WriteOnly)) + file.write(logRules.array()); + } +}; + +class tst_QLogger : public QObject +{ + Q_OBJECT + +private: + QStringList logEntries; + +private slots: + void initTestCase() + { + oldMessageHandler = qInstallMessageHandler(myCustomMessageHandler); + + //prepare for testcase log with NOT callin qSetLoggingRules & Co + //Only the QT_LOGGING_CONFIG environment variable should activate the logging + //qDebug & co are redefined to avoid creating the QLogger private instance uncontrolled. + QByteArray ba; + ba.append(LOGRULEFILE); + qputenv("QT_LOGGING_CONFIG", ba); + + //create log rules + logRules.addKey("My.Category.*", true); + pFileWriter = new WriteFileThread(); + writeLogRuleFile(); + //Make sure the rule file exists otherwise QtLogger will not be active + QTRY_VERIFY(QFile::exists(LOGRULEFILE)); + } + + void createQtLoggerFromThread() + { + logReceived = false; + LogThread thread; + + //QtLogger private was created not in the main thread. + thread.start(); + thread.wait(); + //Make sure that message handler was called => logger private instance is created + QTRY_VERIFY(logReceived); + } + + void checkFileWatcherTrigger() + { + //Now logger exist + QLoggingPrivate *logger = qtLoggerInstance(); + QTRY_VERIFY(logger->_configFileWatcher); + + //Check filewriter trigger + QSignalSpy spy(logger, SIGNAL(configurationChanged())); + logRules.addKey("My.Category.*", false); + pFileWriter = new WriteFileThread(); + writeLogRuleFile(); + QTRY_VERIFY(spy.count() > 0); + + //Check filewriter trigger again + spy.clear(); + logRules.addKey("My.Category.*", true); + pFileWriter = new WriteFileThread(); + writeLogRuleFile(); + QTRY_VERIFY(spy.count() > 0); + } + + void cleanupTestCase() + { + qInstallMessageHandler(oldMessageHandler); + if (QFile::exists(LOGRULEFILE)) + QFile::remove(LOGRULEFILE); + delete pFileWriter; + } + +private: + void writeLogRuleFile() + { + pFileWriter->start(); + pFileWriter->wait(); + } + + WriteFileThread *pFileWriter; +}; + + +QTEST_MAIN(tst_QLogger) +#include "tst_qloggerenvar.moc" |